package upload

import (
	"fmt"
	"errors"
	"strings"
	"path/filepath"
	"qiniu-upload/etc"

	"golang.org/x/net/context"
	"github.com/qiniu/api.v7/cdn"
	"github.com/qiniu/api.v7/storage"
	"github.com/qiniu/api.v7/auth/qbox"
)

type Upload struct {
	domain    string
	bucket    string
	accessKey string
	secretKey string
	rootDir   string
	expire    uint32
	cover     bool
	base      bool
	result    *Result
}

// 获取上传对象
func NewUpload(domain string, bucket string, accessKey string, secretKey string) *Upload {
	return &Upload{
		domain:    domain,
		bucket:    bucket,
		accessKey: accessKey,
		secretKey: secretKey,
		expire:    600,
		result:    &Result{},
	}
}

// 上传根目录
func (upload *Upload) SetRootDir(rootDir string) *Upload {
	upload.rootDir = rootDir
	return upload
}

// 覆盖上传
func (upload *Upload) SetCover(cover bool) *Upload {
	upload.cover = cover
	return upload
}

// 上传超时时间
func (upload *Upload) SetExpire(expire uint32) *Upload {
	upload.expire = expire
	return upload
}

func (upload *Upload) SetBase(base bool) *Upload {
	upload.base = base
	return upload
}

// 上传文件
func (upload *Upload) UploadFile(fileName string, dir string) (*Result, error) {
	if !etc.IS(fileName) {
		return nil, errors.New(fileName + " is not exists.")
	}

	var key string

	if !upload.base {
		key = upload.key(filepath.Base(fileName), dir)
	} else {
		key = upload.key(fileName, dir)
	}

	if len(key) <= 0 {
		return nil, errors.New(fileName + " create key is error.")
	}

	fmd, err := etc.MD5(fileName)
	if err != nil {
		return nil, errors.New(fileName + " file md5 is error.")
	}

	token := upload.token(key)

	uploader := storage.NewFormUploader(&storage.Config{})
	err = uploader.PutFile(context.Background(), &upload.result, token, key, fileName, nil)
	if err != nil {
		return nil, errors.New(fileName + " " + err.Error())
	}

	upload.result.Md5 = fmd
	upload.result.Url = fmt.Sprintf("%s%s", upload.domain, upload.result.Key)

	return upload.result, nil
}

// 获取上传文件名称
func (upload *Upload) key(fileName string, dir string) string {
	name := strings.Replace(fileName, upload.rootDir, "", -1)
	name = strings.TrimLeft(name, "./")
	name = strings.Replace(name, "\\", "/", -1)
	name = strings.TrimLeft(name, "/")

	key := fmt.Sprintf("%s/%s", strings.Trim(dir, "/"), name)

	return strings.Trim(key, "/")
}

// 获取上传token
func (upload *Upload) token(key string) string {
	var scope string

	mac := qbox.NewMac(upload.accessKey, upload.secretKey)

	if upload.cover {
		scope = fmt.Sprintf("%s:%s", upload.bucket, key)
	} else {
		scope = upload.bucket
	}

	pp := storage.PutPolicy{
		Scope:      scope,
		ReturnBody: `{"key":"$(key)","hash":"$(etag)","fsize":$(fsize)}`,
	}

	pp.Expires = upload.expire

	return pp.UploadToken(mac)
}

// 刷新文件CDN
func (upload *Upload) RefreshUrls(urls []string) error {
	mac := qbox.NewMac(upload.accessKey, upload.secretKey)
	man := cdn.NewCdnManager(mac)

	if _, err := man.RefreshUrls(urls); err != nil {
		return err
	}

	return nil
}

// 刷新目录CDN
func (upload *Upload) RefreshDirs(dirs []string) error {
	mac := qbox.NewMac(upload.accessKey, upload.secretKey)
	man := cdn.NewCdnManager(mac)

	if _, err := man.RefreshDirs(dirs); err != nil {
		return err
	}

	return nil
}
